package cn.biplam.front.template.control.rfFlowTable;

import java.util.ArrayList;

import cn.biplam.common.client.OperatorResult;
import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.KvMap;
import cn.biplam.common.wrapper.Result;
import cn.biplam.common.wrapper.UserInfo;
import cn.biplam.front.callback.CallBack;
import cn.biplam.front.template.control.rfFlowTable.callback.action.ActionCallback;
import cn.biplam.front.template.control.rfFlowTable.callback.content.BaseContentCallback;

/**
 *  有汇总行的表格<BR>
 *  <P>用法:
 *  1 放入维度字段:putDimensionField()<BR>
 *  2 放入指标字段:putIndicateField()<BR>
 *  3 放入其他字段:putField()<BR>
 *  4 绘制表格非汇总行(获取维度值列表前调用):processed()<BR>
 *  5 获取当前表格维度值列表:getDemesionValueList()<BR>
 *  6 设置汇总数据集(在调用get方法获取表格界面前):setSummaryResult()<BR>
 *  </P>
 * @author XiaoRuxing Nov 27, 20095:11:35 PM
 * @version 1.0
 */
public class SummaryRfFlowTable extends RfTable{

	/**
	 * 构造方法
	 * @param mUser			用户信息类
	 * @param sHomeUrl		主页地址
	 * @param tablePageID	表格页面对象ID
	 * @param mainKey       主键字段名称
	 * @param result		操作结果集
	 * @throws ErrorMessage
	 */
	public SummaryRfFlowTable(String homeUrl, UserInfo user,
			String tablePageID, OperatorResult result) throws ErrorMessage {
		super(homeUrl, user, tablePageID, result);
	}

	/**
	 * 放入一个维度字段,指定标题文字、没有动作
	 * @param fieldNames		列字段名
	 * @param fieldCaption		列标题文字
	 * @throws ErrorMessage
	 */
	public void putDimensionField(String fieldName,String fieldCaption) throws ErrorMessage{
		this.putDimensionField(fieldName, fieldCaption,new BaseContentCallback(fieldName));
	}

	/**
	 * 放入一个维度字段,由Callback创建标题文字、没有动作
	 * @param fieldName			列字段名	
	 * @param fieldCaption		列标题文字
	 * @param contentCallback	列内容回调类
	 * @throws ErrorMessage 
	 */
	public void putDimensionField(String fieldName,String fieldCaption,CallBack contentCallback) throws ErrorMessage{
		this.putDimensionField(fieldName, fieldCaption, contentCallback,null);
	}

	/**
	 *  放入维度字段,由Callback创建标题文字、没有动作,有动作
	 * @param fieldName			列字段名	
	 * @param fieldCaption		列标题文字
	 * @param contentCallback	列内容回调类
	 * @param actCallback       动作回调类
	 * @throws ErrorMessage 
	 */
	public void putDimensionField(String fieldName,String fieldCaption,CallBack contentCallback,
			ActionCallback actCallback) throws ErrorMessage{
		this.putField(fieldName, fieldCaption, contentCallback, actCallback);
		this.table.setIsDimensionField(fieldName);
	}

	/**
	 * 放入一个维度字段,指定标题文字、没有动作
	 * @param fieldNames		列字段名
	 * @param fieldCaption		列标题文字
	 * @throws ErrorMessage
	 */
	public void putIndicateField(String fieldName,String fieldCaption) throws ErrorMessage{
		this.putIndicateField(fieldName, fieldCaption,new BaseContentCallback(fieldName));
	}

	/**
	 * 放入一个维度字段,由Callback创建标题文字、没有动作
	 * @param fieldName			列字段名	
	 * @param fieldCaption		列标题文字
	 * @param contentCallback	列内容回调类
	 * @throws ErrorMessage 
	 */
	public void putIndicateField(String fieldName,String fieldCaption,CallBack contentCallback) throws ErrorMessage{
		this.putIndicateField(fieldName, fieldCaption, contentCallback,null);
	}

	/**
	 *  放入维度字段,由Callback创建标题文字、没有动作,有动作
	 * @param fieldName			列字段名	
	 * @param fieldCaption		列标题文字
	 * @param contentCallback	列内容回调类
	 * @param actCallback       动作回调类
	 * @throws ErrorMessage 
	 */
	public void putIndicateField(String fieldName,String fieldCaption,CallBack contentCallback,
			ActionCallback actCallback) throws ErrorMessage{
		this.putField(fieldName, fieldCaption, contentCallback, actCallback);
		this.table.setIsIndicateField(fieldName);
	}

	/**
	 *  设置汇总数据前处理<BR>
	 *  绘制报表,保存维度值列表<BR>
	 *  保存当前粒度值汇总对应的行和列索引<BR>
	 *  汇总时要求清单数据集按照维度排序
	 * @throws ErrorMessage 
	 */
	public void processed() throws ErrorMessage{
		this.table.processed();
	}

	/**
	 *  需要先执行this.processed()才能获取到维度值列表
	 * @return 获取维度值列表(有序的按维度粒度排列,最前面为最粗粒度维度)<BR>
	 *         数组格式为:<维度字段名称,维度字段的值列表(多个值用逗号隔开,不含单引号)>
	 * @throws ErrorMessage 
	 */
	public  KvMap<String, String> getDemesionValueList() throws ErrorMessage{
		return this.table.getDemesionValueList();
	}

	/**
	 *  设置汇总数据集<BR>
	 * @param result 汇总数据集<BR>
	 *               最细粒度下的指标汇总,按照维度进行排序<BR>
	 *               键值对数据格式<维度主键(当前粒度所有维度值合并),<指标名称,统计值>><BR>
	 * @throws ErrorMessage 
	 */
	public void setSummaryResult(Result result) throws ErrorMessage{
		this.table.setSummaryResult(summaryByDimension(result));
	}

	/**
	 *  根据维度汇总数据<BR>
	 * @param result 数据集
	 * @return 返回按照维度树形结构组织的数据
	 * @throws ErrorMessage
	 */
	private SummaryValueOpt summaryByDimension(Result result) throws ErrorMessage{
		SummaryValueOpt virtual = null;
		if(result!=null){
			result.beforeFirst();
			ArrayList<String> dimensions = this.table.dimensionList();
			//维度列表
			virtual = new SummaryValueOpt();
			while(result.next()){
				//创建所有维度节点
				rowDimension(virtual, dimensions, result);
			}
			//统计粗粒度值
			//summaryUpDimension(virtual.getSummary());
		}
		return virtual;
	}

	/**
	 *  对当前行出现维度统计
	 */
	private void rowDimension(SummaryValueOpt firstSummary,
			ArrayList<String> dimensions,Result result) throws ErrorMessage{
		SummaryValueOpt summary = null;
		ArrayList<String> dimensionValues = new ArrayList<String>();
		//firstSummary父粒度
		//对于当前行:从最粗粒度到最细粒度逐渐增加
		//如果当前粒度存在则不创建节点,将当前维度设置为父粒度
		//未找到创建当前维度,将当前维度挂入父亲,将当前维度设置为父粒度
		for(int i=0;i<dimensions.size();i++){
			//获取当前维度字段名称
			String curentDimensionName = dimensions.get(i);
			//获取当前维度值
			String curentDimensionValue = result.getString(curentDimensionName);
			//当前行维度值增加
			if(curentDimensionValue==null){
				continue;
			}
			dimensionValues.add(curentDimensionValue);
			//查找当前维度是否已经存在
			SummaryValue find = firstSummary.search(dimensionValues);
			//如果当前粒度存在则不创建节点,将当前维度设置为父粒度
			if(find!=null){
				firstSummary = new SummaryValueOpt(find);
				summaryIndicate(find, result);
				continue;
			}
			summary = new SummaryValueOpt();
			//当前统计的维度
			summary.addDimension(dimensionValues);
			//将当前维度挂入父亲
			firstSummary.addChild(summary.getSummary());
			//如果当前粒度为最细粒度设置当前维度的统计值
			addIndicate(summary, result);
			//将当前维度设置为父粒度
			firstSummary = summary;
		}
	}

	/**
	 *  指标计算
	 */
	private void addIndicate(SummaryValueOpt summary,
			Result result) throws ErrorMessage{
		//如果当前粒度为最细粒度设置当前维度的统计值
		for(String indicate:this.table.indicateList()){
			summary.addIndicateValue(
					TOOLS.stringToFloat(result.getString(indicate))
			);
		}
	}
	
	/**
	 *  粗粒度指标计算
	 */
	private void summaryIndicate(SummaryValue summary,
			Result result) throws ErrorMessage{
		//如果当前粒度为最细粒度设置当前维度的统计值
		int i=0;
		for(String indicate:this.table.indicateList()){
			if(summary.indicateValue.size()>i){
				summary.indicateValue.set(i,summary.indicateValue.get(i)+TOOLS.stringToFloat(result.getString(indicate)));
			}else{
				new SummaryValueOpt(summary).addIndicateValue(
						TOOLS.stringToFloat(result.getString(indicate)));
			}
		}
	}
	
	/**
	 * 统计,将数据集中所有指标按照维度的不同粒度进行统计计算(目前默认为求和)
	 */
	class SummaryValue{
		/** 维度 */
		protected ArrayList<String> dimensions;
		/** 指标 */
		protected ArrayList<Float> indicateValue;
		/** 比当前粒度更粗一级粒度的统计值 */
		protected SummaryValue parent;
		/** 比当前粒度更细一级粒度的统计值 */
		protected ArrayList<SummaryValue> childs;
	}

	class SummaryValueOpt{

		private SummaryValue summary;

		public SummaryValueOpt(){
			this(null);
		}

		public SummaryValueOpt(SummaryValue summary){
			if(summary!=null){
				this.summary = summary;
			}else{
				this.summary = new SummaryValue();
			}
		}

		/**
		 *  添加当前统计的维度
		 * @param dimensionValue 维度值
		 */
		protected void addDimension(String dimensionValue){
			if(this.summary.dimensions==null)
				this.summary.dimensions = new ArrayList<String>();
			this.summary.dimensions.add(dimensionValue);
		}

		/**
		 *  添加当前统计的维度
		 * @param dimensionValue 维度值(多个维度值)
		 */
		protected void addDimension(ArrayList<String> dimensionValue){
			if(this.summary.dimensions==null)
				this.summary.dimensions = new ArrayList<String>();
			this.summary.dimensions.addAll(dimensionValue);
		}

		/**
		 *  设置最细粒度的当前统计值,依次添加
		 * @param value 统计值
		 */
		protected void addIndicateValue(Float... value){
			if(this.summary.indicateValue == null){
				this.summary.indicateValue = new ArrayList<Float>();
			}
			for(Float f:value){
				this.summary.indicateValue.add(f);
			}
		}

		/**
		 *  将子系粒度统计指标求和作为当前粒度的指标值
		 * @throws ErrorMessage 
		 */
		protected void sumChilds() throws ErrorMessage{
			if(this.summary.childs==null
					|| this.summary.childs.size()<1)return;
			if(this.summary.indicateValue == null){
				this.summary.indicateValue = new ArrayList<Float>();
			}
			for(SummaryValue child:this.summary.childs){
				//将所有当前粒度下的细粒度相加汇总
				if(child.indicateValue==null)throw new ErrorMessage("Node "+TOOLS.listToString(child.dimensions)+" indicate is null SummaryValue!");
				for(int i=0;i<child.indicateValue.size();i++){
					//当前指标汇总
					if(i<this.summary.indicateValue.size()){
						this.summary.indicateValue.set(i, 
								this.summary.indicateValue.get(i)+child.indicateValue.get(i));
					}else{
						this.summary.indicateValue.add(child.indicateValue.get(i));
					}
				}
			}
		}

		/**
		 *  添加当前统计的更粗粒度统计
		 * @param parent
		 */
		protected void setParent(SummaryValue parent){
			this.summary.parent = parent;
		}

		/**
		 *  添加当前统计的更细粒度统计
		 * @param child
		 */
		protected void addChild(SummaryValue child){
			if(this.summary.childs==null)
				this.summary.childs = new ArrayList<SummaryValue>();
			this.summary.childs.add(child);
		}

		/**
		 *  查找节点
		 * @param demesions 维度值(查找时按照维度进行查找,维度值和顺序)
		 * @return 匹配当前维度的节点
		 */
		protected SummaryValue search(String... demesions){
			ArrayList<String> list = new ArrayList<String>();
			TOOLS.stringArrayToList(list, demesions);
			return this.search(list);
		}

		/**
		 *  查找节点
		 * @param demesions 维度值(查找时按照维度进行查找,维度值和顺序)
		 * @return 匹配当前维度的节点
		 */
		protected SummaryValue search(ArrayList<String> list){
			//空节点
			if((this.summary.dimensions == null && list ==null) ||
					(this.summary.dimensions != null &&this.summary.dimensions.equals(list))
					)
				return this.summary;
			ArrayList<SummaryValue> findValue = new ArrayList<SummaryValue>();
			this.search(summary, list, findValue);
			if(findValue.size()>0){
				return findValue.get(0);
			}
			else{
				return null;
			}
		}


		/**
		 * @return 获取当前维度指标
		 */
		protected SummaryValue getSummary(){
			return this.summary;
		}

		/**
		 *  查找节点
		 */
		private void search(SummaryValue summary,ArrayList<String> dimesions,
				ArrayList<SummaryValue> findValue){
			if(summary.childs==null)return;
			for(SummaryValue child:summary.childs){
				if(child.dimensions.equals(dimesions)){
					findValue.add(child);
					return;//找到节点直接返回
				}else{
					search(child,dimesions,findValue);
				}
			}
		}
	}

	/**
	 * 统计计算方式
	 */
	enum Summary_Model{
		/** 求和 */
		Sum,
		/** 求最大值 */
		Max
	}
}
